有德國股神之稱的 安德烈·科斯托蘭尼(André Kostolany)在其著作《一個投機者的告白》中提到:「在指數上漲過程中,即使是最差的投機人士也能賺到一些錢;而在指數下跌過程中,即使挑到好股票的人也賺不到錢。因此投資最看重的是普遍的趨勢,其次才是選股。」
順應市場方向,多頭市場不做空,空頭市場不做多,是趨勢追隨者在市場生存的基本原則。
大盤的風險,稱為 系統性風險、市場風險,通常是受政治、經濟等大環境因素影響,導致所有股票受波及,因為這是無法靠分散投資消除的風險,所以又稱為 不可分散風險。我們觀察大盤走勢就是為了趨吉避凶,因為「覆巢之下無完卵」,當大盤表現不佳時,個股普遍都是下跌情形,所以科斯托蘭尼說:「根據經驗,沒有人的選股技術,可以好到即使股市普遍下跌也能賺到錢。」
在本系列文中,我們將投資分為三個層次,分別是 大盤、產業 與 個股。如下圖所示,確認大盤處於上升趨勢後,再挑選表現強勁的產業,然後從產業中選擇理想的個股。

因此,在進行選股程序之前,我們會先著重於大盤分析,確認整體市場的方向是上升趨勢、下降趨勢或橫盤整理,然後再由上而下順勢而為。如同著名的股票作手 傑西.李佛摩 (Jessie Livermore) 提出的 最小阻力線 的概念:「在執行交易以前,確認市場的最小阻力線與你的操作同向後,才能建立操作部位。」
為了瞭解大盤趨勢,我們需要取得最近一段期間的大盤指數與市場成交資訊,以確認市場目前處在的位置。
「由上而下」或「由下而上」投資法並沒有好壞之分,不過投資與選股畢竟是主觀的過程,按筆者習慣以及文章編排方式,本系列文採用由上而下的投資策略。
在證交所網站的 每日市場成交資訊 頁面,可以按年月份查詢集中市場成交資訊。
證交所首頁 > 交易資訊 > 盤後資訊 > 每日市場成交資訊
在「每日市場成交資訊」頁面,選擇「資料日期」按下「查詢」後,就會列出資料日期所屬年月份的資料。

點擊「列印 / HTML」連結,瀏覽器會開新分頁將資訊輸出成可列印的 HTML 頁面。假設資料日期為「民國 111 年 07 月」,我們會得到以下 URL:
https://www.twse.com.tw/exchangeReport/FMTQIK?response=html&date=20220701
以上 URL 可設定的參數如下:
response:回應資料的格式。指定 html 輸出 HTML 文件;改為 csv 可以另存 CSV 檔案;設定成 json 或不指定則回應 JSON 格式資料。date:資料日期。接受的日期格式為 yyyyMMdd,如 20220701。若不指定資料日期或輸入無效的日期格式,則預設回應最新年月份的市場成交資訊。我們將 URL 查詢參數改為 response=json&date=20220701,證交所就會以 JSON 格式資料回應 2022 年 7 月 的集中市場成交資訊:
{
  "stat": "OK",
  "date": "20220701",
  "title": "111年07月市場成交資訊",
  "fields": [
    "日期",
    "成交股數",
    "成交金額",
    "成交筆數",
    "發行量加權股價指數",
    "漲跌點數"
  ],
  "data": [
    [
      "111/07/01",
      "7,861,837,121",
      "308,665,002,335",
      "2,761,795",
      "14,343.08",
      "-482.65"
    ]
  ],
  "notes": [
    "當日統計資訊含大盤、零股、盤後定價及鉅額交易,不含拍賣、標購。",
    "外幣成交值係以本公司當日下午3時30分公告匯率換算後加入成交金額。<br>公告匯率請參考本公司首頁>產品與服務>交易系統>雙幣ETF專區>代號對應及每日公告匯率。"
  ]
}
取得 JSON 格式資料後,我們要整理集中市場成交資訊就比較容易了,其他由證交所提供的盤後資訊大多都可以使用這種方式取得。
在實作取得集中市場成交資訊的方法前,我們先安裝以下套件方便我們處理日期資料與數字格式的轉換:
$ npm install --save luxon numeral
$ npm install --save-dev @types/luxon @types/numeral
以上安裝的套件用途說明如下:
luxon:用於處理日期資料,由於知名套件 Moment.js 已不再維護,我們使用原團隊成員開發的 Luxon 作為替代品。numeral:用於處理數字資料,我們從證交所及櫃買中心取得資料時,會遇到大量需要將 string 轉換成 number 型別的需求,使用該套件幫助我們做數字格式的轉換。@types/luxon:提供 luxon 的型別定義檔 (Declaration Files)。@types/numeral:提供 numeral 的型別定義檔 (Declaration Files)。以上套件安裝完成後,開啟 src/scraper/twse-scraper.service.ts 檔案,在 TwseScraperService 實作 fetchMarketTrades() 方法,取得集中市場成交資訊:
import * as cheerio from 'cheerio';
import * as iconv from 'iconv-lite';
import * as numeral from 'numeral';
import { DateTime } from 'luxon';
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
@Injectable()
export class TwseScraperService {
  constructor(private httpService: HttpService) {}
  ...
  async fetchMarketTrades(date: string) {
    // 將 `date` 轉換成 `yyyyMMdd` 格式
    const formattedDate = DateTime.fromISO(date).toFormat('yyyyMMdd');
    // 建立 URL 查詢參數
    const query = new URLSearchParams({
      response: 'json',     // 指定回應格式為 JSON
      date: formattedDate,  // 指定資料日期
    });
    const url = `https://www.twse.com.tw/exchangeReport/FMTQIK?${query}`;
    // 取得回應資料
    const responseData = await firstValueFrom(this.httpService.get(url))
      .then(response => (response.data.stat === 'OK') && response.data);
    // 若該日期非交易日或尚無成交資訊則回傳 null
    if (!responseData) return null;
    // 整理回應資料
    const data = responseData.data
      .map(row => {
        // [ 日期, 成交股數, 成交金額, 成交筆數, 發行量加權股價指數, 漲跌點數 ]
        const [ date, ...values ] = row;
        // 將 `民國年/MM/dd` 的日期格式轉換成 `yyyy-MM-dd`
        const [ year, month, day ] = date.split('/');
        const formatted = `${+year + 1911}${month}${day}`;
        const formattedDate = DateTime.fromFormat(formatted, 'yyyyMMdd').toISODate();
        // 轉為數字格式
        const [ tradeVolume, tradeValue, transaction, price, change ]
          = values.map(value => numeral(value).value());
        return {
          date: formattedDate,
          tradeVolume,
          tradeValue,
          transaction,
          price,
          change,
        };
      })
      .find(data => data.date === date) || null;  // 取得目標日期的成交資訊
    return data;
  }
}
在 fetchMarketTrades() 方法中,需要指定 date 參數,表示要取得市場成交資訊的日期。我們定義回傳的物件欄位包含如下:
date:日期tradeVolume:成交股數tradeValue:成交金額transaction:成交筆數price:發行量加權股價指數change:漲跌點數完成後,我們只要呼叫 TwseScraperService 的 fetchMarketTrades() 方法,就可以按日期取得集中市場成交資訊。以日期 2022-07-01 為例:
{
  date: '2022-07-01',
  tradeVolume: 7861837121,
  tradeValue: 308665002335,
  transaction: 2761795,
  price: 14343.08,
  change: -482.65
}
在櫃買中心網站的 日成交量值指數 頁面,可以按年、月份查詢櫃買市場成交資訊。
櫃買中心首頁 > 上櫃 > 盤後資訊 > 日成交量值指數
在「日成交量值指數」頁面,選擇「資料年月」後,就會列出該年月份的資料。

點擊「列印/匯出HTML」連結,瀏覽器會開新分頁將資訊輸出成可列印的 HTML 頁面。假設資料年月為「111/07」,我們會得到以下 URL:
https://www.tpex.org.tw/web/stock/aftertrading/daily_trading_index/st41_result.php?l=zh-tw&d=111/07&s=0,asc,0&o=htm
以上 URL 可設定的參數如下:
l:輸出資料的語系。zh-tw 為正體中文;en-us 為英文。d:資料年月,接受的日期格式為 民國年/MM,若指定成 民國年/MM/dd 也會得到跟 民國年/MM 一樣的結果。需要注意,若 l 參數指定為 en-us,則 d 參數需改為 yyyy/MM 的日期格式。s:指定欄位依照升冪或降冪排序。例如 1,asc,0 是按成交股數(仟股)升冪排序;2,desc,0 則按金額(仟元)降冪排序,依此類推。o:資料輸出的格式。指定 htm 表示輸出 HTML 文件;改為 csv 可以另存 CSV 檔案;設定成 json 或不指定則回應 JSON 格式資料。我們將 URL 查詢參數改為 l=zh-tw&d=111/07&o=json,櫃買中心就會以 JSON 格式資料回應 2022 年 7 月的櫃買市場成交資訊:
{
  "reportDate": "111/07",
  "iTotalRecords": 1,
  "aaData": [
    [
      "111/07/01",
      "845,221,570",
      "67,600,392,538",
      "577,204",
      "173.03",
      "-8.06"
    ]
  ]
}
以上回應資料 aaData 欄位的陣列中每個索引值的元素,依序表示為日期、成交股數、成交金額、成交筆數、櫃買指數、漲跌點數。
取得 JSON 格式資料後,我們要整理櫃買市場成交資訊就比較容易了,其他由櫃買中心提供的盤後資訊大多都可以使用這種方式取得。
我們新增一個 TpexScraperService 表示從櫃買中心取得資料的服務。打開終端機使用 Nest CLI 建立 TpexScraperService:
$ nest g service scraper/tpex-scraper --flat --no-spec
Nest CLI 會在 src/scraper 目錄下建立 tpex-scraper.service.ts 檔案,並且將 TpexScraperService 加入至 ScraperModule 的 providers 設定。
開啟 src/scraper/tpex-scraper.service.ts 檔案,在 TpexScraperService 實作 fetchMarketTrades() 方法,取得櫃買市場成交資訊:
import * as numeral from 'numeral';
import { DateTime } from 'luxon';
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
@Injectable()
export class TpexScraperService {
  constructor(private httpService: HttpService) {}
async fetchMarketTrades(date: string) {
    // 將 `date` 轉換成 `民國年/MM` 格式
    const dt = DateTime.fromISO(date);
    const year = dt.get('year') - 1911;
    const formattedDate = `${year}/${dt.toFormat('MM')}`;
    // 建立 URL 查詢參數
    const query = new URLSearchParams({
      l: 'zh-tw',         // 指定語系為正體中文
      d: formattedDate,   // 指定日期
      o: 'json',          // 指定回應格式為 JSON
    });
    const url = `https://www.tpex.org.tw/web/stock/aftertrading/daily_trading_index/st41_result.php?${query}`;
    // 取得回應資料
    const responseData = await firstValueFrom(this.httpService.get(url))
      .then(response => (response.data.iTotalRecords > 0) && response.data);
    // 若該日期非交易日或尚無成交資訊則回傳 null
    if (!responseData) return null;
    // 整理回應資料
    const data = responseData.aaData.map(row => {
      // [ 日期, 成交股數, 金額, 筆數, 櫃買指數, 漲/跌 ]
      const [ date, ...values ] = row;
      // 將 `民國年/MM/dd` 的日期格式轉換成 `yyyy-MM-dd`
      const [ year, month, day ] = date.split('/');
      const formatted = `${+year + 1911}${month}${day}`;
      const formattedDate = DateTime.fromFormat(formatted, 'yyyyMMdd').toISODate();
      // 轉為數字格式
      const [ tradeVolume, tradeValue, transaction, price, change ]
        = values.map(value => numeral(value).value());
      return {
        date: formattedDate,
        tradeVolume,
        tradeValue,
        transaction,
        price,
        change,
      };
    })
    .find(data => data.date === date) || null;  // 取得目標日期的成交資訊
    return data;
  }
}
在 fetchMarketTrades() 方法中,需要指定 date 參數,表示要取得市場成交資訊的日期。我們定義回傳的物件欄位包含如下:
date:日期tradeVolume:成交股數tradeValue:成交金額transaction:成交筆數price:櫃買指數change:漲跌點數完成後,我們只要呼叫 TpexScraperService 的 fetchMarketTrades() 方法,就可以按日期取得櫃買市場成交資訊。以日期 2022-07-01 為例:
{
  date: '2022-07-01',
  tradeVolume: 845221570,
  tradeValue: 67600392538,
  transaction: 577204,
  price: 173.03,
  change: -8.06
}
大盤指數是衡量整體股票市場漲跌的重要指標,集中市場的「加權指數」與櫃買市場的「櫃買指數」都是以股票的市值加權計算,市值較高的股票加權比較高,因此權值股的漲跌對於大盤指數有舉足輕重的影響。

Source:富果熱力圖
上圖是 2022 年上半年加權指數成分股按市值大小呈現的熱力圖,我們可以一眼看出「護國神山」台積電(2330)佔了非常大的面積板塊!根據 2022 年 8 月期交所 臺灣證券交易所發行量加權股價指數成分股暨市值比重 的資料顯示,臺股市值第一名的台積電佔大盤比重高達 28%,第二名的鴻海(2317)則是 3.23%,一、二名市值相差之大,台積電稱為「護國神山」當之無愧。因爲台積電市值佔大盤比重非常高,所以台積電在盤中的大漲或大跌,足以帶動整個大盤走勢。
當加權指數收紅,是因為台積電獨強,但其他中小型個股普遍表現不佳時,這個盤勢常被股民戲稱為「拉積盤」。當這個情況發生時,加權指數可能不足以代表整體市場,因此有些資訊廠商甚至設計出「大盤扣除台積電」的指數計算方式。
除了大盤指數外,股市的 上漲家數 及 下跌家數 也是另一種衡量市場表現的方式,這通常被稱為 市場寬幅(Market Breadth)指摽。以 2022 年初至 8 月 31 日的集中市場為例,共發生 12 次加權指數上漲,但上漲家數卻小於下跌家數的情形!尤其在 2022 年 1 月 4 日、2 月 10 日及 7 月 15 日,加權指數上漲超過百點,但整體市場的下跌家數卻比上漲家數還要多,此時投資人的持股部位若沒有權值股,對於大盤指數上漲可能會「無感」。
| 日期 | 加權指數 | 漲跌 | 漲跌幅 | 上漲家數 | 下跌家數 | 
|---|---|---|---|---|---|
| 2022-01-04 | 18526.35 | +255.84 | +1.40% | 380 | 460 | 
| 2022-01-11 | 18288.21 | +48.83 | +0.27% | 236 | 637 | 
| 2022-01-12 | 18375.40 | +87.19 | +0.48% | 420 | 435 | 
| 2022-01-13 | 18436.93 | +61.53 | +0.33% | 412 | 433 | 
| 2022-01-24 | 17989.04 | +89.74 | +0.50% | 278 | 585 | 
| 2022-02-10 | 18338.05 | +186.29 | +1.03% | 385 | 449 | 
| 2022-03-29 | 17548.66 | +28.65 | +0.16% | 422 | 425 | 
| 2022-07-15 | 14550.62 | +112.10 | +0.78% | 401 | 469 | 
| 2022-07-20 | 14733.22 | +39.14 | +0.27% | 406 | 454 | 
| 2022-07-22 | 14949.36 | +11.66 | +0.08% | 418 | 440 | 
| 2022-08-03 | 14777.02 | +29.79 | +0.20% | 188 | 700 | 
| 2022-08-16 | 15420.57 | +3.22 | +0.02% | 395 | 445 | 
Source:臺灣證券交易所
當大盤指數可能無法反映整體市況時,這時候觀察股票市場的上漲及下跌家數就會比較客觀。許多用來衡量市場寬幅的技術指標如 騰落指標(ADL)、漲跌比率(ADR)、超買超賣指標(OBOS)等,都是利用市場每個交易日的上漲家數及下跌家數計算而來,藉此反映整體市場行情漲升力道與強弱變化,進一步研判出未來行情可能的發展方向。
在證交所網站的 每日收盤行情 頁面,可以按日期查詢集中市場上漲及下跌家數。
證交所首頁 > 交易資訊 > 盤後資訊 > 每日收盤行情
在「每日收盤行情」頁面,選取「日期」並在「分類項目」選擇「大盤統計資訊」後按下「查詢」,就會列出該日大盤統計資訊。

在頁面下方可以找到「漲跌證券數合計」。

點擊「列印 / HTML」連結,瀏覽器會開新分頁將資訊輸出成可列印的 HTML 頁面。假設資料日期為「民國 111 年 07 月 01 日」,我們會得到以下 URL:
https://www.twse.com.tw/exchangeReport/MI_INDEX?response=html&date=20220701&type=MS
以上 URL 可設定的參數如下:
response:回應資料的格式。指定 html 輸出 HTML 文件;改為 csv 可以另存 CSV 檔案;設定成 json 或不指定則回應 JSON 格式資料。date:資料日期。接受的日期格式為 yyyyMMdd,如 20220701。type:分類項目。MS 代表「大盤統計資訊」。我們將 URL 查詢參數改為 response=json&date=20220701,證交所就會以 JSON 格式資料回應 2022 年 7 月 1 日的大盤統計資訊:
{
  "fields8": [
    "類型",
    "整體市場",
    "股票"
  ],
  "subtitle8": "漲跌證券數合計",
  "data8": [
    [
      "上漲(漲停)",
      "2,375(4)",
      "58(1)"
    ],
    [
      "下跌(跌停)",
      "6,635(157)",
      "873(15)"
    ],
    [
      "持平",
      "199",
      "22"
    ],
    [
      "未成交",
      "18,478",
      "1"
    ],
    [
      "無比價",
      "1,968",
      "11"
    ]
  ],
  ......
}
因為回應資料較長,以上我們簡化了資料只顯示重要的部分。JSON 欄位 data8 的內容即是漲跌證券數合計。「整體市場」包含了權證,權證又包含了看多的認購權證(Call Warrant)以及看空的認售權證(Put Warrant),無法實際判斷大盤的多空情形,因此我們只需要取得「股票」欄的上漲及下跌家數即可。
若在 URL 的 date 參數輸入了非交易日日期或資料尚未更新,則證交所會回應:
{
  "stat": "很抱歉,沒有符合條件的資料!"
}
開啟 src/scraper/twse-scraper.service.ts 檔案,在 TwseScraperService 實作 fetchMarketBreadth() 方法,取得集中市場上漲及下跌家數:
import * as cheerio from 'cheerio';
import * as iconv from 'iconv-lite';
import * as numeral from 'numeral';
import { DateTime } from 'luxon';
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
@Injectable()
export class TwseScraperService {
  constructor(private httpService: HttpService) {}
  ...
  async fetchMarketBreadth(date: string) {
    // 將 `date` 轉換成 `yyyyMMdd` 格式
    const formattedDate = DateTime.fromISO(date).toFormat('yyyyMMdd');
    // 建立 URL 查詢參數
    const query = new URLSearchParams({
      response: 'json',     // 指定回應格式為 JSON
      date: formattedDate,  // 指定資料日期
      type: 'MS',           // 指定類別為大盤統計資訊
    });
    const url = `https://www.twse.com.tw/exchangeReport/MI_INDEX?${query}`;
    // 取得回應資料
    const responseData = await firstValueFrom(this.httpService.get(url))
      .then(response => (response.data.stat === 'OK') && response.data);
    // 若該日期非交易日或尚無成交資訊則回傳 null
    if (!responseData) return null;
    // 整理回應資料
    const raw = responseData.data8.map(row => row[2]);  // 取股票市場統計
    const [ up, limitUp, down, limitDown, unchanged, unmatched, notApplicable ] = [
      ...raw[0].replace(')', '').split('('),  // 取出漲停家數
      ...raw[1].replace(')', '').split('('),  // 取出漲停家數
      ...raw.slice(2),
    ].map(value => numeral(value).value());   // 轉為數字格式
    const data = {
      date,
      up,
      limitUp,
      down,
      limitDown,
      unchanged,
      unmatched: unmatched + notApplicable, // 未成交(含暫停交易)家數
    };
    return data;
  }
}
在 fetchMarketBreadth() 方法中,需要指定 date 參數,表示要取得上漲及下跌家數的日期。我們定義回傳的物件欄位包含如下:
date:日期up:上漲家數limitUp:漲停家數down:下跌家數limitDown:跌停家數unchanged:平盤家數unmatched:未成交家數完成後,我們只要呼叫 TwseScraperService 的 fetchMarketBreadth() 方法,就可以按日期取得集中市場上漲及下跌家數。以日期 2022-07-01 為例:
{
  date: '2022-07-01',
  up: 58,
  limitUp: 1,
  down: 873,
  limitDown: 15,
  unchanged: 22,
  unmatched: 12
}
在櫃買中心網站的 上櫃股票市場現況 頁面,可以按日期查詢櫃買市場上漲及下跌家數。
櫃買中心首頁 > 上櫃 > 盤後資訊 > 上櫃股票市場現況
在「上櫃股票市場現況」頁面,選取「資料日期」後,就會列出該日市場現況,並找到上漲及下跌家數統計。

點擊「列印/匯出HTML」連結,瀏覽器會開新分頁將資訊輸出成可列印的 HTML 頁面。假設資料年月為「111/07/01」,我們會得到以下 URL:
https://www.tpex.org.tw/web/stock/aftertrading/market_highlight/highlight_result.php?l=zh-tw&o=htm&d=111/07/01
以上 URL 可設定的參數如下:
l:輸出資料的語系。zh-tw 為正體中文;en-us 為英文。o:資料輸出的格式。指定 htm 表示輸出 HTML 文件;改為 csv 可以另存 CSV 檔案;設定成 json 或不指定則回應 JSON 格式資料。d:資料日期,接受 民國年/月/日 的日期格式。需要注意,若 l 參數指定為 en-us,則 d 參數需改成 西元年/月/日 的日期格式。我們將 URL 查詢參數改為 l=zh-tw&d=111/07/01&o=json,櫃買中心就會以 JSON 格式資料回應 111 年 7 月 1 日的上櫃市場現況:
{
  "reportDate": "111/07/01",
  "iTotalRecords": 9,
  "listedNum": "799",
  "capital": "769,889",
  "companyValue": "4,240,980",
  "tradeAmount": "67,619",
  "tradeVolumn": "845,321",
  "close": "173.03",
  "change": "-8.06",
  "upNum": "76",
  "upStopNum": "0",
  "downNum": "689",
  "downStopNum": "27",
  "noChangeNum": "22",
  "noTradeNum": "12",
  "rptNote": "標的物:等價與鉅額成交之股票、換股權利證書,不含可轉債、認購售權證、認股權憑證及不動產受益憑證"
}
以上資料欄位 upNum 為上漲家數;upStopNum 為漲停家數;downNum 為下跌家數;downStopNum 為跌停家數;noChangeNum 為平盤家數;noTradeNum 為未成交(含暫停交易)家數。
開啟 src/scraper/tpex-scraper.service.ts 檔案,在 TpexScraperService 實作 fetchMarketBreadth() 方法,取得櫃買市場上漲及下跌家數:
import * as numeral from 'numeral';
import { DateTime } from 'luxon';
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
@Injectable()
export class TpexScraperService {
  constructor(private httpService: HttpService) {}
  ...
  async fetchMarketBreadth(date: string) {
    // `date` 轉換成 `民國年/MM/dd` 格式
    const dt = DateTime.fromISO(date);
    const year = dt.get('year') - 1911;
    const formattedDate = `${year}/${dt.toFormat('MM/dd')}`;
    // 建立 URL 查詢參數
    const query = new URLSearchParams({
      l: 'zh-tw',         // 指定語系為正體中文
      d: formattedDate,   // 指定日期
      o: 'json',          // 指定回應格式為 JSON
    });
    const url = `https://www.tpex.org.tw/web/stock/aftertrading/market_highlight/highlight_result.php?${query}`;
    // 取得回應資料
    const responseData = await firstValueFrom(this.httpService.get(url))
      .then(response => (response.data.iTotalRecords > 0) && response.data);
    // 若該日期非交易日或尚無成交資訊則回傳 null
    if (!responseData) return null;
    // 整理回應資料
    const { upNum, upStopNum, downNum, downStopNum, noChangeNum, noTradeNum } = responseData;
    const [ up, limitUp, down, limitDown, unchanged, unmatched ] = [
      upNum, upStopNum, downNum, downStopNum, noChangeNum, noTradeNum
    ].map(value => numeral(value).value());   // 轉為數字格式
    const data = {
      date,
      up,
      limitUp,
      down,
      limitDown,
      unchanged,
      unmatched,
    };
    return data;
  }
}
在 fetchMarketBreadth() 方法中,需要指定 date 參數,表示要取得上漲及下跌家數的日期。我們定義回傳的物件欄位包含如下:
date:日期up:上漲家數limitUp:漲停家數down:下跌家數limitDown:跌停家數unchanged:平盤家數unmatched:未成交家數完成後,我們只要呼叫 TpexScraperService 的 fetchMarketBreadth() 方法,就可以按日期取得櫃買市場上漲及下跌家數。以日期 2022-07-01 為例:
{
  date: '2022-07-01',
  up: 76,
  limitUp: 0,
  down: 689,
  limitDown: 27,
  unchanged: 22,
  unmatched: 12  
}
本系列文已正式出版為《Node.js 量化投資全攻略:從資料收集到自動化交易系統建構實戰》。本書新增了全新內容和實用範例,為你提供更深入的學習體驗!歡迎參考選購,開始你的量化投資之旅!
天瓏網路書店連結:https://www.tenlong.com.tw/products/9786263336070